/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ace.game.entity.weapon;

import ace.game.entity.enemy.Enemy;
import ace.game.entity.bullet.Bullet;
import ace.game.Sprite;
import ace.game.entity.Entity;
import ace.geometry.Vector2D;
import ace.geometry.Vertex2D;
import ace.system.StateManager;
import ace.system.Utilities;
import java.util.Vector;
import javax.microedition.lcdui.Graphics;

/**
 *
 * @author Hallucinogen
 */
public class Weapon extends Entity {
	protected Weapon() {
		//Initialize
		position		= new Vertex2D();
		mReloadTime		= 0;
		mBullets		= new Vector();
		mDeleteBulles	= new Vector();
        mWaveReloadTime = 0;
        mWaveShotCount  = 0;
	}

	public Weapon(WeaponData data) {
		//Initialize
		this();

		//Initialize data
		mData	= data;
	}

	public WeaponData getData()	{	return mData;       }
    public Vector getBullets() {    return mBullets;    }

	public void update(long time) {
		mData.getSprites().update(time);

		// shoot bullet!
        final int reloadTime = mData.getReloadTime();
        if (mWaveReloadTime >= mData.getWaveReload()) {
            mReloadTime += time;
            if (mReloadTime > reloadTime) {
                if (mWaveShotCount < mData.getBulletPerWave()) {
                    mReloadTime -= reloadTime;
                    ++mWaveShotCount;

                    final int splitCount    = mData.getSplitCount();
                    final int spreadCount   = mData.getSpreadCount();

                    for (int i = 0; i < spreadCount; ++i) {
                        final int spreadAngle = -SPREAD_GAP / 2 * (spreadCount - 1) + i * SPREAD_GAP;
                        final double spreadRadian = Math.toRadians(spreadAngle);
                        int nowX    = 0;
                        int nowY    = 0;
                        float dx1   = 0;
                        float dy1   = 0;

                        if (mData.isSeeking() && mTarget != null && mTarget.isAlive()) {
                            dx1    = mTarget.position.x - position.x;
                            dy1    = mTarget.position.y - position.y;
                        } else {
                            dx1    = 0;
                            dy1    = -1000.0f / (float)mData.getBulletData().getDuration();
                        }
                        float dx = dx1 * (float)Math.cos(spreadRadian) - dy1 * (float)Math.sin(spreadRadian);
                        float dy = dx1 * (float)Math.sin(spreadRadian) + dy1 * (float)Math.cos(spreadRadian);
                        float mag   = (float)Math.sqrt(dx * dx + dy * dy);
                        float bulletSpeed = 1000.0f / (float)mData.getBulletData().getDuration();
                        Vector2D velocity = new Vector2D();

                        if (mag > 0) {
                            velocity.x = -dx / mag * bulletSpeed;
                            // TODO: remove 0.05f part, that's super hack!
                            velocity.y = -dy / mag * bulletSpeed + 0.05f;
                            final int constant = splitCount == 1 ? 0 : -SPLIT_GAP * (splitCount - 1) / 2;
                            nowX = (int)((float)constant * dy / mag);
                            nowY = -(int)((float)constant * dx / mag);
                        } else {
                            velocity.x = 0;
                            velocity.y = 0;
                            dx = 1;
                            dy = 0;
                            mag = 1;
                        }
                        for (int j = 0; j < splitCount; ++j) {
                            Vertex2D newPosition = new Vertex2D(position);
                            newPosition.add(velocity);
                            newPosition.x   += nowX;
                            newPosition.y   += nowY;
                            nowX += (int)((float)SPLIT_GAP * dy / mag);
                            nowY -= (int)((float)SPLIT_GAP * dx / mag);
                            if (mData.isSeeking() && mTarget != null && mTarget.isAlive()) {
                                // TODO: for now seeking delay is constant in 500 ms
                                mBullets.addElement(new Bullet(mData.getBulletData(), newPosition, new Vector2D(-velocity.x / 15, -velocity.y / 15), mTarget, 500));
                            } else {
                                mBullets.addElement(new Bullet(mData.getBulletData(), newPosition, new Vector2D(velocity)));
                            }
                        }
                    }
                } else {
                    mWaveShotCount  = 0;
                    mWaveReloadTime = 0;
                    mReloadTime     = 0;
                }
            }
        } else {
            mWaveReloadTime += time;
        }

		updateBullets(time);
    }

	private void updateBullets(long time) {
		// update each bullets
		for (int i = 0, n = mBullets.size(); i < n; ++i) {
			Bullet bullet = (Bullet)mBullets.elementAt(i);

			bullet.update(time);
			if (!bullet.isActive()) {
				mDeleteBulles.addElement(bullet);
			}
		}

		// delete bullets
		for (int i = 0, n = mDeleteBulles.size(); i < n; ++i) {
			Bullet bullet = (Bullet)mDeleteBulles.elementAt(i);

			mBullets.removeElement(bullet);
		}
		mDeleteBulles.removeAllElements();
	}

	public void draw(Graphics g, int startX, int startY, int endX, int endY) {
        // draw bullets
		drawBullets(g, startX, startY, endX, endY);

		//Get current sprite
		Sprite Current = mData.getSprites();
		if (Current == null) return;

		//Get rect
		int Left	= (int)(position.x - startX);
		int Top		= (int)(position.y - startY);

		//Ensure in drawing area
		if (Left + Current.getWidth() < 0)					return;
		else if(Left > StateManager.instance().getWidth())	return;
		else if (Top + Current.getHeight() < 0)				return;
		else if (Top > StateManager.instance().getHeight())	return;

		//Draw sprite
		Current.setPosition(Left, Top);
		Current.draw(g, Graphics.VCENTER | Graphics.HCENTER);
	}

	public void drawBullets(Graphics g, int startX, int startY, int endX, int endY) {
		for (int i = 0, n = mBullets.size(); i < n; ++i) {
			Bullet bullet = (Bullet)mBullets.elementAt(i);

			bullet.draw(g, startX, startY, endX, endY);
		}
	}

    public void setNextTarget(Enemy target) {
        mTarget = target;
    }

	// Data
	protected WeaponData mData;

	// Gameplay
	private int mReloadTime;
    protected int mWaveReloadTime;
    protected int mWaveShotCount;
	private Vector mBullets;
	private Vector mDeleteBulles;
    private Enemy mTarget;

    private final static int SPLIT_GAP = 8;
    private static final int SPREAD_GAP = 360 / Utilities.MAX_SHOT_SPREAD;
}
